#######################################################
# Example of Experimental Framework and Processors    #
# Author: moonho.hwang@gmail.com                      #
#   Date: Oct.19.2011                                 #
#######################################################
from XSY.DEVS.CoupledDEVS import *
from XSY.DEVS.SimEngine import SimEngine
from XSY.DEVS.VeriEngine import VeriEngine
from XSY.DEVS.examples.DEVSs.Transducer import Transducer
from XSY.DEVS.examples.SDEVSs.GeneratorFS import Generator
from XSY.DEVS.examples.STDEVSs.ProcessorST import Processor
from XSY.DEVS.examples.DEVSs.Buffer import Buffer
from XSY.Set.Interval import TInterval

########################## Two classes of moving entities are considered ################################
class A:
   def __int__(self):
      pass 
   def __str__(self):
      return "A"

class B:
   def __int__(self):
      pass 
   def __str__(self):
      return "B"
#######################################################################################################

######################################### Processor Network #############################################
# +--------------------+                        +---------------------------------------------------+ #
# |          EF        |                        |       +--------------+    PB     +------------+   | #
# | +-------+          |                        |       |    Buffer    |           |Processor_i ||  | #
# | |  Gen  >!out ----->!gen_out -------+------->?in---->?in      gatei<-----+----<!out_signal  ||  | #
# | | Auto  <?pull-----<?gen_pull       |       |       |              |     ^     |            ||  | #
# | +-------+          |                |       |       |              |     |     |            ||  | #
# |                    |                |       |       |         gatei>-----|----->?in         ||  | #
# | +-------+          |                |       |       |              |     |     |            ||  | #
# | | Tran  <?sys_in---<?sys_in <-------'       |       +--------------+     |     |            ||  | #
# | |       <?sys_out--<?sys_out<---------------<!out------------------------+----<!out         ||  | #
# | +-------+          |                        |                                  +============++  | #
# +--------------------+                        +---------------------------------------------------+ #
#######################################################################################################

def makeExperimentFrame():
   cm = CoupledDEVS("EF")
   gen = Generator(n="Gen", bAuto = True, OutTable={A:.7, B:.3}, IntGenTimeRV=TInterval(2,5))  
   trans = Transducer("tr")
   cm.addComponents(gen, trans)
   cm.addInputPorts("?gen_pull", "?sys_in", "?sys_out")
   cm.addOutputPorts("!gen_out")
   cm.addCouples((gen.OP["!out"], cm.OP["!gen_out"]), (cm.IP["?gen_pull"], gen.IP["?pull"]),
                 (cm.IP["?sys_in"], trans.IP["?sys_in"]), (cm.IP["?sys_out"], trans.IP["?sys_out"]))
   return cm

def makeProcessorsBuffer(no_procs):
   PB = CoupledDEVS("PB")
   PB.addInputPorts("?in")
   PB.addOutputPorts("!out")
   buf = Buffer("buf", no_procs)
   PB.addComponents(buf)
   PB.addCouples( (PB.IP["?in"], buf.IP["?in"]) )

   for i in xrange(1, no_procs+1):
      s = "proc%d"%i
      proc = Processor(s, meant=10)
      PB.addComponents(proc) 
      gate = "gate%d"%i
      PB.addCouples( (proc.OP["!out"], PB.OP["!out"]) )
      PB.addCouples( (buf.OP[gate],         proc.IP['?in']), 
                    (proc.OP['!out'],        buf.IP[gate]),
                    (proc.OP['!out_signal'], buf.IP[gate]))
   return PB

def makeEF_ProcessorBufferNetwork(no_procs):
   EF = makeExperimentFrame()
   PB = makeProcessorsBuffer(no_procs) # 

   cm = CoupledDEVS("sys") # try it out 
   cm.addComponents(EF, PB) 
   cm.addCouples( (EF.OP["!gen_out"], EF.IP["?sys_in"]), (EF.OP["!gen_out"], PB.IP["?in"]), 
                  (PB.OP["!out"],  EF.IP["?sys_out"]) )
   return cm

def runSimulation(md):
   engine = SimEngine(md)

   #---- setting simulation modes  ----
   #engine.StepByStep = True
   engine.sfactor = float('inf')
   engine.simTimeBound = 5000
   engine.TotalSimRuns = 3
   engine.bVerbose = False
   engine.bAutoresetByTimebound = True
   #----------------------------------------------------
   engine.runInteractiveMenu()
   pass

############################################################################################################
if __name__ == '__main__':
   no_procs = int(raw_input('input # of process: '))
   md = makeEF_ProcessorBufferNetwork(no_procs)
   runSimulation(md)
 
   print "good bye~!" 
